/*
 * Copyright 2013-2019 Xia Jun(3979434@qq.com).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************************************
 *                                                                                     *
 *                        Website : http://www.farsunset.com                           *
 *                                                                                     *
 ***************************************************************************************
 */
package com.farsunset.cim.sdk.server.slc.handler.tcp;

import com.farsunset.cim.acceptor.config.SocketConfig;
import com.farsunset.cim.auth.BlacklistHandler;
import com.farsunset.cim.coder.protobuf.AppMessageDecoder;
import com.farsunset.cim.coder.protobuf.AppMessageEncoder;
import com.farsunset.cim.coder.protobuf.WebMessageDecoder;
import com.farsunset.cim.coder.protobuf.WebMessageEncoder;
import com.farsunset.cim.constant.CIMConstant;
import com.farsunset.cim.constant.ChannelAttr;
import com.farsunset.cim.handler.CIMRequestHandler;
import com.farsunset.cim.handler.LoggingHandler;
import com.farsunset.cim.model.Ping;
import com.farsunset.cim.model.SentBody;
import com.farsunset.cim.sdk.server.slc.handler.BaseNioSocketAcceptor;
import io.netty.bootstrap.AbstractBootstrap;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.epoll.EpollDatagramChannel;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.Duration;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

abstract public class NioSocketAcceptor2 extends BaseNioSocketAcceptor {

    private final EventLoopGroup bossGroup;
    private final EventLoopGroup workerGroup;

    protected NioSocketAcceptor2(SocketConfig socketConfig, boolean usePlatformOptimization) {
        super(socketConfig, usePlatformOptimization);

        ThreadFactory bossThreadFactory = r -> {
            Thread thread = new Thread(r);
            thread.setName(getBossThreadName() + thread.getId());
            return thread;
        };

        ThreadFactory workerThreadFactory = r -> {
            Thread thread = new Thread(r);
            thread.setName(getWorkerThreadName() + thread.getId());
            return thread;
        };

        if (isLinuxSystem()) {
            bossGroup = new EpollEventLoopGroup(bossThreadFactory);
            workerGroup = new EpollEventLoopGroup(workerThreadFactory);
        } else {
            bossGroup = new NioEventLoopGroup(bossThreadFactory);
            workerGroup = new NioEventLoopGroup(workerThreadFactory);
        }

    }

    /**
     * 执行注销SOCKET服务
     */
    @Override
    public void destroy() {
        if (bossGroup != null && !bossGroup.isShuttingDown() && !bossGroup.isShutdown()) {
            try {
                bossGroup.shutdownGracefully();
            } catch (Exception ignore) {
            }
        }

        if (workerGroup != null && !workerGroup.isShuttingDown() && !workerGroup.isShutdown()) {
            try {
                workerGroup.shutdownGracefully();
            } catch (Exception ignore) {
            }
        }
    }

    protected ServerBootstrap createServerBootstrap() {
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workerGroup);
        bootstrap.childOption(ChannelOption.TCP_NODELAY, true);
        bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
        bootstrap.channel(isLinuxSystem() ? EpollServerSocketChannel.class : NioServerSocketChannel.class);
        return bootstrap;
    }

    protected String getBossThreadName() {
        return "nio-boss-";
    }

    protected String getWorkerThreadName() {
        return "nio-worker-";
    }

    protected EventLoopGroup getBossGroup() {
        return bossGroup;
    }

    protected EventLoopGroup getWorkerGroup() {
        return workerGroup;
    }
}
